package org.cliff.codegen;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.cliff.codegen.model.ColumnModel;
import org.cliff.codegen.model.DataBaseModel;
import org.cliff.codegen.model.TableModel;
import org.cliff.codegen.model.TemplateInfo;

/**
 * 绫籆odeGenMain.java鐨勫疄鐜版弿杩帮細浠ｇ爜鐢熸垚鍏ュ彛
 *
 * @author JianLin.Zhu 2015-7-27 涓嬪崍4:40:53
 */
public class CodeGenMain {

	/** @param args */
	public static void main(String[] args) {
		try {
			InputStream in = CodeGenMain.class.getClassLoader().getResourceAsStream("codegen.properties");
			Properties p = new Properties();
			p.load(in);
			in.close();

			String outputdir = p.getProperty("outputdir", "./output/"); // 杈撳嚭鐩綍,鍙慨鏀�,姣斿鏀逛负D:/output

			DataBaseModel dataBaseModel = loadDataBaseModel(p);
			String templateSourceDir = "./template/"; // 妯℃澘鏍圭洰褰曪紝涓嶅缓璁慨鏀�
			List<TemplateInfo> list = TemplateConfig.ReadConfigXml("./template/template.xml"); // 璇诲彇妯＄増閰嶇疆鏂囦欢
			for (int i = 0; i < list.size(); i++) {
				TemplateInfo templateInfo = list.get(i);
				System.out.println("start deal template:" + templateInfo.getTemplateName());
				Generator.generateTableContext(
						dataBaseModel, templateInfo, outputdir, templateSourceDir); // 杩涜琛ㄦā鐗堢敓鎴�
				System.out.println("finish " + templateInfo.getTemplateName());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/** 鍔犺浇鏁版嵁搴搒chema */
	private static DataBaseModel loadDataBaseModel(Properties p) throws Exception {
		DataBaseModel dataBaseModel = new ReadMysql().genarateMysqlDataBase(p);
		return dataBaseModel;
	}

	public static class ReadMysql {

		public DataBaseModel genarateMysqlDataBase(Properties p) {
			// --------------鐢熸垚浠ｇ爜鍓嶄慨鏀瑰涓嬮厤缃畇tart----------------------------//
			String host = p.getProperty("host");
			String database = p.getProperty("database");
			String user = p.getProperty("user");
			String pass = p.getProperty("pass");
			String packname = p.getProperty("packname"); // bean鎵�灞炵粍,榛樿鐢ㄧ┖瀛楃涓插嵆鍙�
			String tableNamePrefix = p.getProperty("tableNamePrefix"); // 璁剧疆琛ㄥ悕鍓嶇紑
			String tablename = p.getProperty("tablename"); // 澶氫釜鐢ㄩ�楀彿鍒嗛殧鍗冲彲
			String author = p.getProperty("author", "JianLin.Zhu");
			// --------------鐢熸垚浠ｇ爜鍓嶄慨鏀瑰涓嬮厤缃� end----------------------------//

			DataBaseModel db = new DataBaseModel();
			db.setDataBaseName(database);
			db.setAuthor(author); // 璁剧疆绛惧悕
			Connection conn = null;
			try {
				List<TableModel> tableModelList = new ArrayList<TableModel>();
				conn = DBManager.mysql(host, database, user, pass);
				if (tablename.length() > 0) {
					tableModelList.addAll(
							parseBatchTable(conn, packname, tablename.split(","), tableNamePrefix));
				} else {
					tableModelList.addAll(parseAllTable(conn, packname, tableNamePrefix));
				}

				//				List<TableModel> tempTableModelList = new ArrayList<TableModel>();
				for (TableModel tm : tableModelList) {
					//					List<ColumnModel> tempList = new ArrayList<ColumnModel>();
					List columnList = tm.getColumnList();
					for (int i = 0; i < columnList.size(); i++) {
						ColumnModel cm = (ColumnModel) columnList.get(i);
						System.out.println("ColumnChineseName:" + cm.getColumnChineseName());
						System.out.println("ColumnJavaName: " + cm.getColumnJavaName());
						System.out.println("ColumnName: " + cm.getColumnName());
						System.out.println("ColumnName2Camel: " + cm.getColumnName2Camel());
						System.out.println("ColumnName2Pascal: " + cm.getColumnName2Pascal());
						System.out.println("ColumnType " + cm.getColumnType());
						System.out.println("CoulmnSize " + cm.getCoulmnSize());
						System.out.println("CoulmnTypeNoSize " + cm.getCoulmnTypeNoSize());
						System.out.println("IsPK " + cm.getIsPK());
					}

					System.out.println(tm.getDomainNameWithFirstCaseLower());
				}

				db.setTableModelList(tableModelList);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
				// setTips("鎵句笉鍒癕ySQL鐨刯ar鍖�");
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return db;
		}

		/** 寮�濮嬪鐞嗙敓鎴愭墍鏈夎〃 濡傛灉涓嶄紶鍏ヨ〃鍚嶏紝琛ㄧず灏嗘暟鎹簱涓墍鏈夎〃鐢熸垚bean; 鍙互鎸囧畾琛ㄥ悕鐢熸垚bean; */
		public List<TableModel> parseAllTable(
				Connection conn, String packname, String tableNamePrefix) {
			List<TableModel> result = new ArrayList<TableModel>();
			String sql = "show tables";
			ResultSet rs = DBManager.query(conn, sql);
			try {
				while (rs.next()) {
					String tablename = rs.getString(1);
					result.add(parseTableByShowCreate(conn, tablename, packname, tableNamePrefix));
				}
				DBManager.close(conn, null, rs);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return result;
		}

		/** 寮�濮嬪鐞嗙敓鎴愭墍鏈夎〃 濡傛灉涓嶄紶鍏ヨ〃鍚嶏紝琛ㄧず灏嗘暟鎹簱涓墍鏈夎〃鐢熸垚bean; 鍙互鎸囧畾琛ㄥ悕鐢熸垚bean; */
		public List<TableModel> parseBatchTable(
				Connection conn, String packname, String[] tables, String tableNamePrefix) {
			List<TableModel> result = new ArrayList<TableModel>();
			for (String tablename : tables) {
				result.add(parseTableByShowCreate(conn, tablename, tableNamePrefix, packname));
			}
			return result;
		}

		/**
		 * 閫氳繃 mysql鐨� show create table TABLE_NAME閫嗗悜鐢熸垚Bean;
		 *
		 * @param conn
		 * @param tname
		 * @param outputdir
		 * @param packname
		 */
		private TableModel parseTableByShowCreate(
				Connection conn, String tablename, String tableNamePrefix, String packname) {
			TableModel table = new TableModel();
			table.setTableName(tablename);
			table.setModuleName(packname);
			table.setTableNamePrefix(tableNamePrefix);
			List<ColumnModel> columnList = new ArrayList<ColumnModel>();
			table.setColumnList(columnList);
			boolean shouldCloseConn = false;
			String sql = "show create table " + tablename;
			ResultSet rs = null;

			try {
				rs = DBManager.query(conn, sql);
				while (rs.next()) {

					String sqlstr = rs.getString(2);
					String lines[] = sqlstr.split("\r\n");
					for (int i = 0; i < lines.length; i++) {
						String line = lines[i];
						//正则匹配所有字段信息
						String regex =
								"\\s*`([^`]*)`\\s*(\\w+[^ ]*)\\s*([a-z]+\\s*)?(NOT\\s+NULL\\s*)?(DEFAULT\\s*([^ ]*|NULL|'0'|''|CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)\\s*)?(\\s*AUTO_INCREMENT\\s*)?(COMMENT\\s*'([^']*)')?\\s*,\\s*";
						//正则匹配主键信息
						String pkRefex = "(?<=PRIMARY KEY \\()\\S+(?<!\\))";
						Matcher matcher = Pattern.compile(pkRefex).matcher(line);
						String pks[] = null;
						if(matcher.find()){
							pks = matcher.group(0).replace("`", "").split(",");
						}

						Pattern p = Pattern.compile(regex);
						Matcher m = p.matcher(line);
						while (m.find()) {
							try {
								String field = m.group(1);

								String type = typeTrans(m.group(2));
								if (type == null) {
									System.out.println("unknow type=" + m.group(2));
									continue;
								}
								String jdbcType = typeTransJDBC(m.group(2));
								String cmt = m.group(8);
								// convert to column
								ColumnModel column = new ColumnModel();
								column.setColumnName(field);
								column.setColumnType(type);
								column.setColumnChineseName(cmt == null ? "" : cmt);
								column.setRemark(cmt);
								column.setJdbcType(jdbcType);
								//循环主键 如果是主键将isPK设置成true
								for(String pk : pks){
									if(pk.equalsIgnoreCase(column.getColumnName())){
										column.setIsPK(true);
									}
								}
								columnList.add(column);
							} catch (Exception e) {
								e.printStackTrace();
								// ignore
							}
						}
						if (i == lines.length - 1) {
							String comment = "";
							int index = line.indexOf("COMMENT=");
							if (index != -1) {
								String tmp = line.substring(index + 8);
								comment = tmp.replace("'", "");
							}
							table.setTableChineseName(comment);
						}
					}
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				DBManager.close(shouldCloseConn ? conn : null, null, rs);
			}
			return table;
		}

		/**
		 * mysql鐨勭被鍨嬭浆鎹㈠埌java 绫诲瀷鍙傝�冩枃绔� http://hi.baidu.com/wwtvanessa/blog/item/9fe555945a07bd16d31b70cd.html
		 */
		public String typeTrans(String type) {
			if (type.contains("tinyint")) {
				return "boolean";
			} else if (type.startsWith("int")) {
				return "Integer";
			} else if (type.contains("bigint")) {
				return "Long";
			} else if (type.contains("timestamp")) {
				return "Timestamp";
			} else if (type.contains("date") || type.contains("time") || type.contains("datetime")) {
				return "Date";
			} else if (type.contains("varchar")
					|| type.contains("text")
					|| type.startsWith("char")
					|| type.contains("enum")
					|| type.contains("set")) {
				return "String";
			} else if (type.contains("binary") || type.contains("blob")) {
				return "byte[]";
			} else if (type.contains("decimal")) {
				return "Double";
			} else {
				return null;
			}
		}

		public String typeTransJDBC(String type) {

			if (type.contains("tinyint")) {
				return "BIT";
			} else if (type.startsWith("int")) {
				return "INTEGER";
			} else if (type.contains("bigint")) {
				return "BIGINT";
			} else if (type.startsWith("timestamp") && type.length() > 8) {
				return "TIMESTAMP";
			} else if (type.startsWith("date") | type.startsWith("time") | type.startsWith("datetime")) {
				return "DATE";
			} else if (type.contains("varchar")
					|| type.contains("text")
					|| type.startsWith("char")
					|| type.contains("enum")
					|| type.contains("set")) {
				return "VARCHAR";
			} else if (type.contains("binary")) {
				return "BINARY";
			} else if (type.contains("blob")) {
				return "BLOB";
			} else if (type.contains("decimal")) {
				return "DOUBLE";
			} else {
				return null;
			}
		}

		public String upperFirestChar(String src) {
			return src.substring(0, 1).toUpperCase().concat(src.substring(1));
		}
	}
}
